package api;

import interfaces.Notificable;
import interfaces.Notificador;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

public final class API implements Notificable{
	
	private static API instanciaUnica = null;
	private int tamanioListaSucesos = 40;
	
	List<Notificador> notificadores; //Lista de objetos del dominio
	List<Regla> reglas;
	List<Suceso> sucesos; //Lista de sucesos que ocurrieron en el dominio
						  //La cantidad de sucesos esta limitada por tamanioListaSucesos
	
	private API(){
		this.notificadores = new ArrayList<Notificador>();
		this.reglas = new ArrayList<Regla>();
		this.sucesos = new ArrayList<Suceso>();
	}
	
	private static void crearInstancia(){
		instanciaUnica = new API();
	}
		
	// Eleva una excepcion en caso de que se quiera clonar la clase
	public Object clone() throws CloneNotSupportedException {
		throw new CloneNotSupportedException();
	}
	
	public static API obtenerInstancia(){
		if (instanciaUnica == null) crearInstancia();
		return instanciaUnica;
	}	
	
	public void registrarNotificador(Notificador objeto){
		//Me fijo de no repetirlo
		if (!this.notificadores.contains(objeto)){
			this.notificadores.add(objeto);
			objeto.registrarObservador(this);
		}		
	}
	
	public void quitarNotificador(Notificador objeto){
		if (this.notificadores.contains(objeto)){
			this.notificadores.remove(objeto);
		}
	}
	
	public List<Regla> getReglas(){
		return this.reglas;
	}
	
	public void setReglas(List<Regla> reglas){
		this.reglas = reglas;
	}
	
	public void registrarRegla(Regla regla){
		this.reglas.add(regla);
	}
	
	public void quitarRegla(Regla regla){
		this.reglas.remove(regla);
	}
	
	//Registra un suceso generado por algun objeto, y se le notifica a todos los objetos
	public void registrarSuceso(Suceso suceso){
		this.insertarSuceso(suceso);
		this.controlarReglas();
	}
	
	//Controla si se cumple alguna regla, y si se cumple, la ejecuta
	private void controlarReglas() {
		Iterator<Regla> itR = this.reglas.iterator();
		while (itR.hasNext()) {
			Regla r = itR.next();
			if (r.verificarRegla()){
				
				if (r.getImportancia().equals("Informativa")) {
					JOptionPane.showMessageDialog(new JFrame(), "Regla informativa cumplida", "Dialog",
							JOptionPane.INFORMATION_MESSAGE);
				}else if (r.getImportancia().equals("Critica")) {
					JOptionPane.showMessageDialog(new JFrame(), "Regla critica cumplida", "Dialog",
							JOptionPane.WARNING_MESSAGE);
				}
				r.ejecutar();
			} 
		}
	}

	// Inserta el suceso verificando la cantidad de elementos
	private void insertarSuceso(Suceso suceso) {	
		List<Suceso> sucesos = this.getSucesos();
		if (sucesos.size() == this.getTamanioListaSucesos()){
			this.eliminarSuceso(sucesos.get(0));		
		}		
		suceso.cancelarSucesos(sucesos);
		sucesos.add(suceso);		
	}
	
	//Elimina un suceso de la lista de la API y de la lista de todos los objetos registrados
	private void eliminarSuceso(Suceso suceso){
		if (this.sucesos.contains(suceso)){
			this.sucesos.remove(suceso);
		}
	}
	
	//Marca un suceso como cancelado
	public void cancelarSuceso(Suceso suceso){
		if (this.sucesos.contains(suceso)){
			this.sucesos.get(this.sucesos.indexOf(suceso)).setCancelado(true);
		}
	}

	public List<Notificador> getNotificadores() {
		return this.notificadores;
	}

	public List<Suceso> getSucesos() {
		return sucesos;
	}	
	
	public void resetear(){
		this.notificadores.clear();
		this.sucesos.clear();
	}
	
	public int getTamanioListaSucesos(){
		return this.tamanioListaSucesos;
	}

	public void notificarMensaje(String mensaje) {
		Suceso suceso = new Suceso(mensaje);
		this.registrarSuceso(suceso);
	}
}
